package com.paomi.client.widget;

import android.app.Activity;
import android.content.Context;
import android.support.annotation.ColorRes;
import android.support.annotation.LayoutRes;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.AdapterView;
import android.widget.FrameLayout;

import com.paomi.client.R;
import com.paomi.client.widget.click.SingleClick;

import static com.paomi.client.utils.DeviceUtils.dipToPX;


/**
 * Created by LS on 2017/5/27 0027.
 * 弹窗基类，接收View显示，{@link Builder#setGravity(int)}, 控制位置
 * 内部处理了返回键逻辑
 */

public class BaseDialog {

    private Builder builder;
    protected ViewGroup decorView;
    public View contentView;
    private Context context;
    public boolean isCancelable;
    public boolean backCancelable;
    private FrameLayout rootView;
    private boolean isDismissing;

    protected Animation dialogInAnim;
    protected Animation dialogOutAnim;
    private OnClickListener onClickListener;
    /**
     *  true 点击外围区域 dismiss
     *  false 点击外围区域事件穿透
     */
    private boolean isRootCanClick;

    public BaseDialog(Context context) {
        this.context = context;
    }

    public BaseDialog(Builder builder) {
        this.builder = builder;
        this.context = builder.getContext();
        initBuilderDialog();
    }

    protected void initBuilderDialog() {
        Activity activity = (Activity) builder.getContext();
        onClickListener = builder.getOnClickListener();
        isRootCanClick = builder.isRootCanClick();
        backCancelable = builder.isBackCancelable();

        decorView = (ViewGroup) activity.getWindow().getDecorView().findViewById(android.R.id.content);

        rootView = new FrameLayout(context);
        final View titleView = decorView.findViewById(R.id.title_view);
        if (titleView != null) {
//            builder.setOutMarginTop(titleView.getBottom());
            if(titleView.getBottom() == 0) {
                titleView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                    @Override
                    public void onGlobalLayout() {
                        titleView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                        initParams(titleView);
                    }
                });
            } else {initParams(titleView);}
        } else initParams(null);
    }

    public void initParams(View titleView) {
        if(titleView != null)builder.setOutMarginTop(titleView.getBottom());
//        builder.setOutMarginTop(DeviceUtils.dipToPX(50));
        rootView.setLayoutParams(builder.getRootLayoutParams());
        rootView.setBackgroundColor(builder.getBackGroundColor());
        rootView.setId(R.id.dialog_root);

        contentView = builder.getContentView();
        contentView.setFocusable(true);
        contentView.setFocusableInTouchMode(true);
//        FrameLayout.LayoutParams contentParams = (FrameLayout.LayoutParams) contentView.getLayoutParams();
//        if(contentParams == null)
        isCancelable = builder.isOutSideCancelable();

        contentView.setOnKeyListener(keyListener);
        if (isRootCanClick)
            rootView.setOnClickListener(rootOnClick);
        rootView.addView(contentView);

        contentView.setLayoutParams(builder.getContentLayoutParams());

        bindView(contentView);
        contentView.requestFocus();

        if (Gravity.BOTTOM == builder.getGravity()) {
            dialogInAnim = AnimationUtils.loadAnimation(context, R.anim.dialog_bottom_in);
            dialogOutAnim = AnimationUtils.loadAnimation(context, R.anim.dialog_bottom_out);
        } else if (Gravity.TOP == builder.getGravity()) {
            dialogInAnim = AnimationUtils.loadAnimation(context, R.anim.dialog_top_in);
            dialogOutAnim = AnimationUtils.loadAnimation(context, R.anim.dialog_top_out);
        } else {
            dialogInAnim = AnimationUtils.loadAnimation(context, R.anim.dialog_center_in);
            dialogOutAnim = AnimationUtils.loadAnimation(context, R.anim.dialog_center_out);
        }
    }

    /** 设置rootView布局是否可点击，事件是否穿透*/
    public void setRootCanClick(boolean isRootCanClick) {
        this.isRootCanClick = isRootCanClick;
        if(rootView != null) rootView.setClickable(isRootCanClick);
    }

    /**
     * 当dialog的内容需要外部数据填充时可重写此方法填充，这里考虑泛型实现
     *
     * @param contentView
     */
    public void bindView(View contentView) {}

    public void setContentView(View contentView) {
        this.contentView = contentView;
        this.contentView.setLayoutParams(builder.getContentLayoutParams());

        bindView(this.contentView);
    }

    public void setContentViewRes(@LayoutRes int layoutRes) {
        this.contentView = View.inflate(context, layoutRes, null);
    }

    /**
     * Loop among the views in the hierarchy and assign listener to them
     */
    private void assignClickListenerRecursively(View parent) {
        if (onClickListener == null || parent == null) {
            return;
        }

        if (parent instanceof ViewGroup) {
            ViewGroup viewGroup = (ViewGroup) parent;
            int childCount = viewGroup.getChildCount();
            for (int i = childCount - 1; i >= 0; i--) {
                View child = viewGroup.getChildAt(i);
                assignClickListenerRecursively(child);
            }
        }
        setClickListener(parent);
    }

    /**
     * It is used to setListener on view that have a valid id associated
     */
    private void setClickListener(View view) {
        if (view.getId() == View.NO_ID) {
            return;
        }
        //adapterview does not support click listener
        if (view instanceof AdapterView) {
            return;
        }

        view.setOnClickListener(new View.OnClickListener() {
            @SingleClick
            @Override
            public void onClick(View v) {
                if (onClickListener == null) {
                    return;
                }
                onClickListener.onClick(BaseDialog.this, v);
            }
        });
    }

    public void show(){
        if(isShowing()) return;
        onAttached(rootView);
    }

    public boolean isShowing() {
        return rootView.getParent() != null;
    }

    public void dismissNoAnimation() {
        decorView.post(new Runnable() {
            @Override
            public void run() {
                decorView.removeView(rootView);
                isDismissing = false;
                if (listener != null) listener.onDismiss();
            }
        });
    }

    public void dismiss() {
        if(isDismissing || !isShowing()) return;
        dialogOutAnim.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {

            }

            @Override
            public void onAnimationEnd(Animation animation) {
                decorView.post(new Runnable() {
                    @Override
                    public void run() {
                        decorView.removeView(rootView);
                        isDismissing = false;
                        if (listener != null) listener.onDismiss();
                    }
                });
            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });
        contentView.startAnimation(dialogOutAnim);
        isDismissing = true;
    }

    /**
     * It is called when the show() method is called
     *
     * @param view is the dialog plus view
     */
    protected void onAttached(View view) {
        decorView.addView(view);
        contentView.startAnimation(dialogInAnim);
        assignClickListenerRecursively(contentView);
        contentView.requestFocus();
        if(listener != null) listener.onShow();
    }

    private View.OnClickListener rootOnClick = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if(isCancelable) dismiss();
        }
    };

    private View.OnKeyListener keyListener = new View.OnKeyListener() {
        @Override
        public boolean onKey(View v, int keyCode, KeyEvent event) {
            switch (event.getAction()) {
                case KeyEvent.ACTION_UP:
                    if (keyCode == KeyEvent.KEYCODE_BACK) {
                        if(!backCancelable)return true; // 禁用物理返回键

                        if (isCancelable) {
                            dismiss();
                            return true;
                        }
                    }
                    break;
                default:
                    break;
            }
            return false;
        }
    };

    public void toggle() {
        if(isDismissing) return;
        if(isShowing()) {
            dismiss();
        }else {
            show();
        }
    }

    private OnDialogDismissListener listener;

    public void setOnDialogDismissListener(OnDialogDismissListener listener) {
        this.listener = listener;
    }

    public interface OnDialogDismissListener {
        void onDismiss();
        void onShow();
    }

    /**
     * 构建dialog
     */
    public static class Builder {
        private Context context;

        private OnClickListener listener;

        /**
         * 外部区域可取消
         */
        private boolean outSideCancelable = true;

        private int gravity = Gravity.CENTER;

        /**
         * 填充布局
         */
        private View contentView;

        /**
         * 背景颜色
         */
        private int backGroundColor = R.color.color_black_60;

        /**
         * 设置dialog外间距
         */
        private final int[] outMostMargin = new int[4];

        /**
         * dialog填充布局参数
         */
        private final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.BOTTOM
        );
        /**
         * 事件穿透，设置背景透明和false
         */
        private boolean rootCanClick = true;
        /** 物理返回键是否可用*/
        private boolean backCancelable = true;

        public Builder(Context context) {
            this.context = context;
//            outMostMargin[1] = dipToPX(50);
        }

        public Context getContext() {
            return context;
        }

        public boolean isOutSideCancelable() {
            return outSideCancelable;
        }

        public Builder setOutSideCancelable(boolean outSideCancelable) {
            this.outSideCancelable = outSideCancelable;
            return this;
        }

        public Builder setBackCancelable(boolean backCancelable) {
            this.backCancelable = backCancelable;
            return this;
        }

        public int getGravity() {
            return gravity;
        }

        public Builder setGravity(int gravity) {
            this.gravity = gravity;
            params.gravity = gravity;
            return this;
        }

        public View getContentView() {
            return contentView;
        }

        public Builder setContentView(View contentView) {
            this.contentView = contentView;
            return this;
        }

        public FrameLayout.LayoutParams getRootLayoutParams() {
            FrameLayout.LayoutParams outParams = new FrameLayout.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT
            );
            outParams.setMargins(outMostMargin[0], outMostMargin[1], outMostMargin[2], outMostMargin[3]);
            return outParams;
        }

        public FrameLayout.LayoutParams getContentLayoutParams() {
            return params;
        }

        /**
         * Add margins to your dialog root view which contains everything. As default they are 0
         * are applied
         */
        public Builder setOutMargin(int left, int top, int right, int bottom) {
            this.outMostMargin[0] = left;
            this.outMostMargin[1] = top;
            this.outMostMargin[2] = right;
            this.outMostMargin[3] = bottom;
            return this;
        }

        /**
         * usually fullScreen or below title, if top 0, fullScreen, otherwise set title height
         */
        public Builder setOutMarginTop(int top) {
            this.outMostMargin[1] = top;
            return this;
        }

        /**
         * Add margins to your dialog content view. As default they are 0
         * are applied
         * note: dp not px
         */
        public Builder setInnerMargin(int left, int top, int right, int bottom) {
            params.setMargins(dipToPX(left), dipToPX(top), dipToPX(right), dipToPX(bottom));
            return this;
        }

        public Builder setContentRes(@LayoutRes int layoutRes) {
            this.contentView = View.inflate(this.getContext(), layoutRes, null);
            return this;
        }

        public int getBackGroundColor() {
            return getContext().getResources().getColor(backGroundColor);
        }

        public Builder setBackGroundColor(@ColorRes int backGroundColor) {
            this.backGroundColor = backGroundColor;
            return this;
        }

        public OnClickListener getOnClickListener() {
            return listener;
        }

        public Builder setOnClickListener(OnClickListener listener) {
            this.listener = listener;
            return this;
        }

        public BaseDialog create() {
            return new BaseDialog(this);
        }

        public boolean isRootCanClick() {
            return rootCanClick;
        }

        public Builder setRootCanClick(boolean rootCancelClick) {
            this.rootCanClick = rootCancelClick;
            return this;
        }

        public boolean isBackCancelable() {
            return backCancelable;
        }
    }

    public interface OnClickListener {
        void onClick(BaseDialog dialog, View v);
    }
}
